
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.spec.InvalidKeySpecException;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import org.aisino.fabric.sdk.AppOrg;
import org.aisino.fabric.sdk.AppStore;
import org.aisino.fabric.sdk.AppUser;
import org.aisino.fabric.sdk.transaction.InvokeorQueryTransaction;
import org.aisino.fabric.utils.ClientConfig;
import org.aisino.fabric.utils.NetworkConfig;
import org.aisino.fabric.utils.SDKUtils;
import org.hyperledger.fabric.sdk.ChaincodeEndorsementPolicy;
import org.hyperledger.fabric.sdk.ChaincodeID;
import org.hyperledger.fabric.sdk.Channel;
import org.hyperledger.fabric.sdk.EventHub;
import org.hyperledger.fabric.sdk.HFClient;
import org.hyperledger.fabric.sdk.Orderer;
import org.hyperledger.fabric.sdk.Peer;
import org.hyperledger.fabric.sdk.ProposalResponse;
import org.hyperledger.fabric.sdk.QueryByChaincodeRequest;
import org.hyperledger.fabric.sdk.TransactionProposalRequest;
import org.hyperledger.fabric.sdk.TxReadWriteSetInfo;
import org.hyperledger.fabric.sdk.User;
import org.hyperledger.fabric.sdk.BlockEvent.TransactionEvent;
import org.hyperledger.fabric.sdk.BlockInfo.EnvelopeType;
import org.hyperledger.fabric.sdk.TransactionRequest.Type;
import org.hyperledger.fabric.sdk.exception.ChaincodeEndorsementPolicyParseException;
import org.hyperledger.fabric.sdk.exception.CryptoException;
import org.hyperledger.fabric.sdk.exception.InvalidArgumentException;
import org.hyperledger.fabric.sdk.exception.ProposalException;
import org.hyperledger.fabric.sdk.exception.TransactionException;
import org.hyperledger.fabric.sdk.security.CryptoSuite;

import com.sun.xml.internal.ws.util.CompletedFuture;

/**
 * Hello world!
 *
 */
public class App {


	public static void query(HFClient client, Channel channel, String cc, String fn, String[] args)
			throws InvalidArgumentException, ProposalException, TransactionException, UnsupportedEncodingException {
		QueryByChaincodeRequest queryByChaincodeRequest = client.newQueryProposalRequest();
		queryByChaincodeRequest.setArgs(args);
		queryByChaincodeRequest.setFcn(fn);
		queryByChaincodeRequest.setChaincodeID(ChaincodeID.newBuilder().setName(cc).build());

		Map<String, byte[]> tm2 = new HashMap<>();
		tm2.put("HyperLedgerFabric", "QueryByChaincodeRequest:JavaSDK".getBytes(UTF_8));
		tm2.put("method", "QueryByChaincodeRequest".getBytes(UTF_8));
		queryByChaincodeRequest.setTransientMap(tm2);

		Collection<ProposalResponse> queryProposals = channel.queryByChaincode(queryByChaincodeRequest, channel.getPeers());
		for (ProposalResponse proposalResponse : queryProposals) {
			if (!proposalResponse.isVerified() || proposalResponse.getStatus() != ProposalResponse.Status.SUCCESS) {
				System.out.println("Failed query proposal from peer " + proposalResponse.getPeer().getName() + " status: " + proposalResponse.getStatus() + ". Messages: "
						+ proposalResponse.getMessage() + ". Was verified : " + proposalResponse.isVerified());
			} else {
				String payload = proposalResponse.getProposalResponse().getResponse().getPayload().toStringUtf8();
				System.out.printf("Query payload of b from peer %s returned %s", proposalResponse.getPeer().getName(), payload);
			}
		}

	}
	
	public static void invoke(HFClient client, Channel channel, String cc, String fn, String[] args)
			throws InvalidArgumentException, ProposalException, TransactionException, UnsupportedEncodingException{
		Collection<ProposalResponse> successful = new LinkedList<>();
		Collection<ProposalResponse> failed = new LinkedList<>();
		TransactionProposalRequest transactionProposalRequest = client.newTransactionProposalRequest();
		transactionProposalRequest.setChaincodeID(ChaincodeID.newBuilder().setName(cc).build());
        transactionProposalRequest.setChaincodeLanguage(Type.GO_LANG);
        //transx	actionProposalRequest.setFcn("invoke");
        transactionProposalRequest.setFcn(fn);
        transactionProposalRequest.setProposalWaitTime(config.getProposalWaitTime());
        transactionProposalRequest.setArgs(args);
        
        ChaincodeEndorsementPolicy itTestPolicy = new ChaincodeEndorsementPolicy();
        try {
			itTestPolicy.fromYamlFile(new File("E:\\fabricsdk\\chaincodeendorsementpolicy.yaml"));
		} catch (ChaincodeEndorsementPolicyParseException e) {
			e.printStackTrace();
		} catch (IOException e) { 
			e.printStackTrace();
		}
        
        transactionProposalRequest.setChaincodeEndorsementPolicy(itTestPolicy);
        
        AppUser user = (AppUser) client.getUserContext();
        
        System.out.println("sending transactionProposal to all peers with arguments: "+fn+"("+args+")");
        
        channel.getPeers().iterator().next().getProperties();	
        
        Collection<ProposalResponse> transactionPropResp = channel.sendTransactionProposal(transactionProposalRequest, channel.getPeers());
        for (ProposalResponse response : transactionPropResp) {
        	if (response.getStatus() == ProposalResponse.Status.SUCCESS) {
                System.out.println(String.format("Successful transaction proposal response Txid: %s from peer %s", response.getTransactionID(), response.getPeer().getName()));
                successful.add(response);
            } else {
                failed.add(response);
            }
		}
        
        Collection<Set<ProposalResponse>> proposalConsistencySets =org.hyperledger.fabric.sdk.SDKUtils.getProposalConsistencySets(transactionPropResp);
        if (proposalConsistencySets.size() != 1) {
        	System.err.println(String.format("Expected only one set of consistent proposal responses but got %d", proposalConsistencySets.size()));
		}
        System.out.println(String.format("Received %d transaction proposal responses. Successful+verified: %d . Failed: %d",
                            transactionPropResp.size(), successful.size(), failed.size()));
        
        if (failed.size() > 0) {
        	ProposalResponse firstTransactionProposalResponse = failed.iterator().next();
        	System.err.println(String.format("Not enough endorsers for "+fn+"("+args+"):" + failed.size() + " endorser error: " +
                                firstTransactionProposalResponse.getMessage() +
                                ". Was verified: " + firstTransactionProposalResponse.isVerified()));
		}
        if (successful.size() == 0) {
        	System.err.println("No successful response!!!");
			return ;
		}
        System.out.println("Successfully received transaction proposal responses.");
        
        System.out.println("Send invoke responses to orderers.");
        Collection<Orderer> orderers = channel.getOrderers();
        while (true) {
        	Collection<Orderer> to = new LinkedList<Orderer>();
        	if (!orderers.iterator().hasNext()) {
        		System.err.println("Send invoke responses to orderers failed!!!");
				break;
			}
        	to.add(orderers.iterator().next());
        	CompletableFuture<TransactionEvent> responses = channel.sendTransaction(successful, to);
        	if (responses.isCompletedExceptionally()) {
				break;
			}
		}
            
        ProposalResponse resp = successful.iterator().next();
        byte[] x = resp.getChaincodeActionResponsePayload(); // This is the data returned by the chaincode.
        String resultAsString = null;
        if (x != null) {
            resultAsString = new String(x, "UTF-8");
        }

        System.out.println("Sending chaincode transaction("+fn+":args: "+args+") to orderer.");
        
	}

}
    